﻿/*
 *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the License); you may
 *  not use this file except in compliance with the License.
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 */


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/sm2.h>
#include <gmssl/error.h>


int test_sm2_points_mul_g(void)
{
	const char *k_hex[] = {
		"D49733EF7322BCA402FF2C55A76226D036293578228F05BB0A084E7FD679DA6A",
		"EE459A3CEA02B64116CA83738284A8673141F2C0800791A5774B3B3326BCBAE9",
		"112C903A44D865817C34050F32A7B7C5562FF21D5FB86F3EBC82E017E63AA650",
	};
	const char *P_hex[] = {
		"DA0A26E5A2FD1A8338E6465CD73EACD360EFD0C0278DD3239174077FD1646D0D"
		"7B5454054D4E799DE8AF8D2BB4E35D34B4C4A286BE6E631691E11A8D878EF0AA",
		"FBEEA44629CCCE80894CCDD66594B391E62A476AD2F401CBF1B64728C6195402"
		"45E6ACF90653E584C6F71A6A130B311B9582977751AE413697398C85D35C4DD4",
		"7D40E2CDA2528106C41D90B654E8BEB52E66BAF2D1F49574992FE707F0BE6223"
		"E4C5F597E924662F2A85C6065F05A2E554D856C8135C34A4BC82870D555F9084",
	};
	uint8_t k[32];
	uint8_t P[64];
	uint8_t x[64];
	uint8_t *y = x + 32;
	size_t len, i;

	for (i = 0; i < sizeof(k_hex)/sizeof(k_hex[0]); i++) {
		hex_to_bytes(k_hex[i], strlen(k_hex[i]), k, &len);
		hex_to_bytes(P_hex[i], strlen(P_hex[i]), P, &len);

		sm2_points_mul(x, y, k, 0, NULL, NULL);

		if (memcmp(x, P, 64) != 0) {
			error_print();
			return -1;
		}
	}

	printf("%s ok\n", __FUNCTION__);
	return 1;
}

int test_sm2_points_mul(void)
{
	const char *k_hex[] = {
		"84890E2149BF27124A123441ED574373C5506293AA087B319A44A8481CFF4201",
		"C80DD28E6093883E8BB637CA8C73CDD43D562D4235E201A83FB5FEF6CE7B0E00",
		"1BFC60372080CDCB4B11A798FE91D15FBB9ACD1B696850DFC84DA4B54B849D92",
		"06104FD237BCA808B3D6039A0A859C7AD46E4FF8358F0E909A65CB0F5E63D07E",
	};
	const char *P_hex[] = {
		"E658713DDCDB7C89431C2F19CE1187CA323620197534AFCFD322EE39CD18CDB8"
		"D1FCD5160877086EF85F5C7CF2F850D0D3D57BA4B2547CB719EE5EDD3A2ACD54",
		"01E9266592CF24B124A8CE2ACA03941A32FA05EADB7EB165207148F0468A32D0"
		"AD576F985A6365EF43654C6F82B151153928C59D0A04BDB8865CBC3370093E7C",
		"F77F4A004CA3ACFC1476D6BE6E74B3724D116CB43913B81CD18C9F67FB684FDD"
		"A64D24AA17DAAFC359D368CA4FB5023552C1C9158C8C63359B8617C12031A723",
		"A56B91BA232C11099C2545F637E0949E943631032592BE3AD063426A54B6D4B9"
		"7E706E500A0D0BCE94A6574889544A8425791C5C1D5E80EBA73B1A4D2FBA85DF",
	};
	const char *Q_hex[] = {
		"D9C7FE8529EC92CD4C371BF031DFBC939DB3A4571C0FBE3BFFAF53016B57A767"
		"995BDFC720CD7504839275029A423172725B2EFD57448A45533727167578257C",
		"9ED9C5F08B7853ABB486B9C62D6E8D76A014A7BBA1967710CF419FBA8D038F15"
		"EB503473E3C401974BD2CD61BFC9B3F84E32B4137F116FBFEC551D604DD654CC",
		"6FDEEC7B9405F75E1F6BD81524AD982A8752AD0093CA356535AFDDD37068D960"
		"1D010E962355349956CC8F0408C5FA945A4F29FC4D7083F9325F392528C40693",
		"2520E6EFB29A073E71B63ABBD93FA2899ABA1940DC942BF628861BD6697B3F6F"
		"BEB40823F2365975B10AA0848E127C72D32F0924323B276413FA267717E0716B",
	};
	uint8_t k[32];
	uint8_t P[64];
	uint8_t Q[64];
	uint8_t R[64];
	size_t len, i;


	for (i = 0; i < sizeof(k_hex)/sizeof(k_hex[0]); i++) {
		hex_to_bytes(k_hex[i], strlen(k_hex[i]), k, &len);
		hex_to_bytes(P_hex[i], strlen(P_hex[i]), P, &len);
		hex_to_bytes(Q_hex[i], strlen(Q_hex[i]), Q, &len);

		sm2_points_mul(R, R + 32, NULL, 1, (SM2_POINT *)P, &k);

		if (memcmp(R, Q, 64) != 0) {
			error_print();
			return -1;
		}
	}

	printf("%s ok\n", __FUNCTION__);
	return 1;
}

int test_sm2_points_mul_mult(void)
{
	const char *s_hex =
		"75B6973113B59FBF4EF91D3986B8EA3548B8DA538611154A4F91049645F36C74";
	const char *k_hex[] = {
		"0E7A0ABB57773AA55F4B829767654D451AB6E7AECF05FFA8DFF41134D5700D40",
		"27F4E552EE458A90FB5A46BC9106799AAF9F51D873E188D148C61154539A272A",
		"2C6C45FFBD27C2F9AFFCEB023F45E16B6A9415BF34A4D94599B6C35B03EAC1F7",
	};
	const char *P_hex[] = {
		"E8346D7CCF6C071C3C8343A305F5AD9EDCE59EF75F64774732F2CED8F3B7143A"
		"D0CF09FDFD9C69775BE47FBA558D3AD904D61D5DB6CC8D9C6F7CA484DFF0182B",
		"E6679FBC4C0E460B1FAB57EA3CD653601BA68223062E6C53B65DF3DE4A566862"
		"124EE9725C6A3FB427B05130B68FD963FB4762DC6EDCC0319B807DB290B3032D",
		"FA6654F72E8DEDD9ED00EA74C81F0CAB37C6D28000E02A2648E7BEB7F22FC118"
		"97F08B2357503E7BBCE7275C336FF1F713DD9B5BE66BFEEC18A6C837E59FD4E6",
	};
	const char *Q_hex =
		"F5F2749B9D36AE0175DC63F3F97D9747B813F63D1475978E8792DD1AB7F13050"
		"1B6951A69477F39550F5550FF783905F3B7305186F38D3A63A8ECCD6E28E1603";

	uint8_t s[32];
	uint8_t k[3][32];
	SM2_POINT P[3];
	uint8_t Q[64];
	uint8_t R[64];
	size_t len, i;

	hex_to_bytes(s_hex, strlen(s_hex), s, &len);
	for (i = 0; i < sizeof(k_hex)/sizeof(k_hex[0]); i++) {
		hex_to_bytes(k_hex[i], strlen(k_hex[i]), k[i], &len);
		hex_to_bytes(P_hex[i], strlen(P_hex[i]), (uint8_t *)&P[i], &len);
	}
	hex_to_bytes(Q_hex, strlen(Q_hex), Q, &len);

	sm2_points_mul(R, R + 32, s, sizeof(k_hex)/sizeof(k_hex[0]), P, k);
	if (memcmp(R, Q, 64) != 0) {
		error_print();
		return -1;
	}

	printf("%s ok\n", __FUNCTION__);
	return 1;
}

int main(void)
{
	if (test_sm2_points_mul() != 1) { error_print(); return -1; }
	if (test_sm2_points_mul_mult() != 1) { error_print(); return -1; }
	printf("%s all tests passed\n", __FILE__);
	return 0;
}
